package communication

import (
	"encoding/json"
	"log"
	"reflect"
	"strconv"
	"sync"
	"time"
)

type Sender struct {
	ClientComm
}

type Receiver struct {
	ClientComm
}

type Client struct {
	name     string
	mu       sync.Mutex
	sender   Sender
	receiver Receiver
	msgMap   map[string]reflect.Type
}

func (client *Client) register(clientComm *ClientComm, clientType string) {
	log.Printf("客户端[%s]正在向服务器注册%s", client.name, clientType)
	clientComm.init(Host, Port)
	msg := RegisterMsg{
		Value: RegisterValue{
			Name:       client.name,
			ClientType: clientType,
		},
	}
	clientComm.sendBytes(buildMessage(&msg))
	log.Printf("客户端[%s] %s 成功连接服务器", client.name, clientType)
}

func (client *Client) Close() {
	client.sender.Close()
	client.receiver.Close()
	log.Printf("客户端[%s]已关闭连接", client.name)
}

func buildMessage(message IMessage) []byte {
	typeOf := reflect.TypeOf(message)
	valueOf := reflect.ValueOf(message)
	for i := 0; i < typeOf.Elem().NumField(); i++ {
		if valueOf.Elem().Field(i).IsZero() {
			def := typeOf.Elem().Field(i).Tag.Get("default")
			if def != "" {
				switch typeOf.Elem().Field(i).Type.String() {
				case "int":
					result, _ := strconv.Atoi(def)
					valueOf.Elem().Field(i).SetInt(int64(result))
				case "uint":
					result, _ := strconv.ParseUint(def, 10, 64)
					valueOf.Elem().Field(i).SetUint(result)
				case "string":
					valueOf.Elem().Field(i).SetString(def)
				}
			}
		}
	}

	res, err := json.Marshal(message)
	if err != nil {
		panic(err)
	}
	return res
}

func parseResult(message IMessage, data []byte) {
	var res ResultMsg
	err := json.Unmarshal(data, &res)
	if err != nil {
		panic(err)
	}

	valueOf := reflect.ValueOf(message)
	field := valueOf.Elem().FieldByName("Result")
	field.Set(reflect.ValueOf(res.Value))
}

func (client *Client) Send(message IMessage) {
	client.mu.Lock()
	defer client.mu.Unlock()
	defer func() {
		if err := recover(); err != nil {
			log.Printf("客户端[%s]发送消息出错：%s", client.name, err)
			time.Sleep(ReconnectTime)
			client.Send(message)
		}
	}()

	if client.sender.conn == nil {
		client.register(&client.sender.ClientComm, "sender")
	}
	msg := buildMessage(message)
	log.Printf("客户端[%s]发送消息到服务器：%s", client.name, msg)
	client.sender.sendBytes(msg)
	ret := client.sender.recvBytes()
	log.Printf("客户端[%s]收到服务器回响应：%s", client.name, ret)
	parseResult(message, ret)
}

func (client *Client) recv() {
	defer func() {
		if err := recover(); err != nil {
			log.Printf("客户端[%s]监听服务器出错：%s", client.name, err)
			time.Sleep(ReconnectTime)
		}
	}()

	var temp struct {
		Cmd    string      `json:"cmd"`
		Value  interface{} `json:"value"`
		Result interface{} `json:"-"`
	}
	msg := client.receiver.recvBytes()
	err := json.Unmarshal(msg, &temp)
	if err != nil {
		panic(err)
	}
	typeOf, ok := client.msgMap[temp.Cmd]
	if !ok {
		log.Printf("客户端[%s]未注册的消息：%s", client.name, temp.Cmd)
		return
	}
	ptr := reflect.New(typeOf.Elem())
	ptr.Elem().FieldByName("Value").Set(reflect.ValueOf(temp.Value))
	obj := ptr.Interface().(IMessage)
	obj.Receive()
	valueOf := reflect.ValueOf(obj)
	res := ResultMsg{
		Value: valueOf.Elem().FieldByName("Result").Interface(),
	}
	client.receiver.sendBytes(buildMessage(&res))
}

func (client *Client) Listen() {
	client.register(&client.receiver.ClientComm, "receiver")

	for {
		client.recv()
	}
}

func (client *Client) Subscribe(message IMessage) {
	typeOf := reflect.TypeOf(message)
	for i := 0; i < typeOf.Elem().NumField(); i++ {
		if typeOf.Elem().Field(i).Tag.Get("json") == "cmd" {
			cmd := typeOf.Elem().Field(i).Tag.Get("default")
			client.msgMap[cmd] = typeOf
			return
		}
	}
}

var instance *Client

func GetClientInstance() *Client {
	if instance == nil {
		instance = &Client{
			name:   "mei_go",
			mu:     sync.Mutex{},
			msgMap: make(map[string]reflect.Type),
		}
	}
	return instance
}
